package cmp.viewer.panels;

import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.sql.ResultSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import util.Debug.ErrorReport;
import util.ui.MenuMapper;
import util.ui.UserPrompt;
import assem.DBConn;
import cmp.dataholders.AlignmentData;
import cmp.dataholders.MultiAlignmentData;
import cmp.main.Globals;
import cmp.viewer.ViewerFrame;
import cmp.viewer.controls.AlignmentPanelBase;
import cmp.viewer.controls.LegendPanel;
import cmp.viewer.controls.MultipleAlignmentPanel;
import cmp.viewer.controls.PairwiseAlignmentPanel;

public class AlignmentViewPanel extends JPanel {
	private static final long serialVersionUID = -2090028995232770402L;
	private static final String [] HELP_TEXT_PAIR_ALIGN = {
		"INSTRUCTIONS:", " ", 
		"Horz. Ratio:     ",
		"    Select the scale in which to view the drawn sequences",
		"Show Sequences: ",
		"    Display the sequences of the alignment(s)",
		"Show Graphic:    ",
		"    Display graphical view of the alignment(s)", " ",
		"Show All:       ",
		"    Show all alignments",
		"Show All Pairs:",
		"    Show all pairs that include the selected sequences",
		"Show Only Pairs: ",
		"    Show the alignments of only the selected sequences", 
		"Note: to select a  sequence, just click on it in any box that contains it " 
	};

		public AlignmentViewPanel(ViewerFrame parentFrame, String [] POGMembers, int mode, String fileName) {
			theParentFrame = parentFrame;
			
			nMode = mode;
			setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
			setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			if(nMode == ViewerFrame.PAIR_MODE)
				buildPairwiseAlignments(POGMembers);
			else
				buildMultiAlignments(POGMembers, fileName);
		}
		
		public AlignmentViewPanel(ViewerFrame parentFrame, int mode, String fileName) {
			theParentFrame = parentFrame;
			
			nMode = mode;
			setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
			setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			if(nMode == ViewerFrame.MULTI_MODE)
				loadMultiAlignments(fileName);
		}
		
		private void buildPairwiseAlignments(String [] POGMembers) {
			final String [] theMembers = POGMembers;
			
			if(theThread == null)
			{
				theThread = new Thread(new Runnable() {
					public void run() {
						try {
							bRunThread = true;
							setStatus();
							//Load sequences from the database
							setPairwiseSequenceData(theMembers);
						
							createButtonPanel();
							createMainPanel();
						
							showStatus(false);
						
							add(buttonPanel);
							add(scroller);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				});
				theThread.setPriority(Thread.MIN_PRIORITY);
				theThread.start();
			}		
		}
		
		private void buildMultiAlignments(String [] POGMembers, String fileName) {
			final String [] theMembers = POGMembers;
			final String theFilename = fileName;
			if(theThread == null)
			{
				theThread = new Thread(new Runnable() {
					public void run() {
						try {
							bRunThread = true;
							setStatus();
							//Load sequences from the database
							setMultiSequenceData(theMembers, theFilename);
						
							createButtonPanel();
							createMainPanel();
						
							showStatus(false);
						
							add(buttonPanel);
							add(scroller);
							
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				});
				theThread.setPriority(Thread.MIN_PRIORITY);
				theThread.start();
			}		
		}
		
		private void loadMultiAlignments(String fileName) {
			final String theFilename = fileName;
			if(theThread == null)
			{
				theThread = new Thread(new Runnable() {
					public void run() {
						try {
							bRunThread = true;
							setStatus();
							//Load sequences from the database
							loadMultiSequenceDataFromCache(theFilename);
						
							createButtonPanel();
							createMainPanel();
						
							showStatus(false);
						
							add(buttonPanel);
							add(scroller);
							
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				});
				theThread.setPriority(Thread.MIN_PRIORITY);
				theThread.start();
			}		
		}
		
		private void setStatus() {
			progressField = new JTextField(100);
			progressField.setEditable(false);
			progressField.setMaximumSize(progressField.getPreferredSize());
			progressField.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			progressField.setBorder(BorderFactory.createEmptyBorder());
			btnCancel = new JButton("Cancel Alignment");
			btnCancel.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			btnCancel.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					stopThread();
				}
			});
			
			add(progressField);
			add(Box.createVerticalStrut(10));
			add(btnCancel);
		}
		
		private void showStatus(boolean show) {
			btnCancel.setVisible(show);
			progressField.setVisible(show);
		}
		
		private void updateStatus(String status) {
			progressField.setText(status);
		}
		
		private void stopThread() {
			if(theThread != null) {
				bRunThread = false;
			}
		}

		private void setPairwiseSequenceData(String [] POGMembers) {
			//Load AA sequences for selected POG members
			String [] POGSeq = getSequences(POGMembers, false);

			Vector<AlignmentData> results = new Vector<AlignmentData> ();

			for(int x=0; x<POGMembers.length && bRunThread; x++) {
				for(int y=x+1; y<POGMembers.length && bRunThread; y++) {
					updateStatus("Aligning " + POGMembers[x] + " and " + POGMembers[y]);
					//Set the pair order alphabetically
					if(POGMembers[x].compareToIgnoreCase(POGMembers[y]) < 0)
						results.add(new AlignmentData(POGMembers[x], POGSeq[x], POGMembers[y], POGSeq[y]));
					else
						results.add(new AlignmentData(POGMembers[y], POGSeq[y], POGMembers[x], POGSeq[x]));
				}
			}
			//Sort by OLP score %
			Collections.sort(results);
			thePairwiseAlignmentData = results.toArray(new AlignmentData[results.size()]);
			createPairwisePanels();
		}
		
	    private String [] getSequences(String [] IDs, boolean isNT) {
	    	ResultSet rset = null;
	    	Vector<String> sequences = null;
	    	try {
		    	DBConn conn = theParentFrame.getDBConnection();

		    	sequences = new Vector<String> ();
	    		for(int x=0; x<IDs.length; x++) {
	    			if(isNT) 
	    				rset = ViewerFrame.executeQuery(conn, "SELECT ntSeq FROM unitrans WHERE UTstr= '" + IDs[x] + "'", null);
	    			else 
	    				rset = ViewerFrame.executeQuery(conn, "SELECT aaSeq FROM unitrans WHERE UTstr= '" + IDs[x] + "'", null);
	    			rset.next();
	    			sequences.add(rset.getString(1));
		    		ViewerFrame.closeResultSet(rset);
	    		}
	    		conn.close();
	    		
	    		return sequences.toArray(new String[sequences.size()]); 
	    	}
	    	catch(Exception e) {
	    		ErrorReport.reportError(e);
	    		return null;
	    	}
	    }

		
		private boolean loadMultiSequenceDataFromCache(String fileName) {
			//TODO hardcoded right now, will replace when db.info is populated
			//Will use getParentFrame().getProjectPath()
			theMultiAlignmentData = new MultiAlignmentData("rhi");
			theMultiAlignmentData.setFilename(fileName);
			if(!theMultiAlignmentData.readMuscleCache()) return false;
			createMultiAlignPanels();
			return true;
		}
		
		private void setMultiSequenceData(String [] POGMembers, String fileName) {
			//Load AA sequences for selected POG members
			String [] POGSeq = getSequences(POGMembers, false);
			
			//TODO hardcoded right now, will replace when db.info is populated
			//Will use getParentFrame().getProjectPath()
			theMultiAlignmentData = new MultiAlignmentData("rhi");
			for(int x=0; x<POGMembers.length; x++) {
				if(POGSeq[x] != null)
					theMultiAlignmentData.addSequence(POGMembers[x], POGSeq[x]);
				else
					System.out.println("Error: no sequence in database for " + POGMembers[x]);
			}
			
			updateStatus("Aligning sequences please wait..");
			theMultiAlignmentData.alignSequences();
			theMultiAlignmentData.setFilename(fileName);
			createMultiAlignPanels();
		}
		
		private void createButtonPanel() {
			buttonPanel = new JPanel();
			buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS));
			buttonPanel.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());

			add(Box.createVerticalStrut(10));
			add(getButtonRow1());
			add(Box.createVerticalStrut(10));
			if(nMode == ViewerFrame.PAIR_MODE) {
				add(getPairwiseButtonRow());
			}

			buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
		}
		
		private JPanel getButtonRow1() {
			JPanel theRow = new JPanel();
			theRow.setLayout(new BoxLayout(theRow, BoxLayout.LINE_AXIS));
			theRow.setAlignmentX(LEFT_ALIGNMENT);
			theRow.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			
			menuHorzRatio = new JComboBox ();
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:1", 1 ) );
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:2", 2 ) );
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:3", 3 ) );
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:4", 4 ) );
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:5", 5 ) );
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:6", 6 ) );
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:7", 7 ) );
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:8", 8 ) );
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:9", 9 ) );
			menuHorzRatio.addItem( new MenuMapper ( "Horz. Ratio = 1:10", 10 ) );
			menuHorzRatio.setBackground(Globals.BGCOLOR);
			menuHorzRatio.setSelectedIndex(0);
			menuHorzRatio.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
						refreshPanels();
				}
			});	
			
			btnShowType = new JButton("Show Sequences");
			btnShowType.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			btnShowType.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					if(btnShowType.getText().equals("Show Graphic")) {
						btnShowType.setText("Show Sequences");
						menuHorzRatio.setEnabled(true);
					}
					else {
						btnShowType.setText("Show Graphic");
						menuHorzRatio.setEnabled(false);
					}
					refreshPanels();
				}
			});
			
			btnCopySeq = new JButton("Copy Sequence");
			btnCopySeq.setEnabled(false);
			btnCopySeq.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			if(nMode == ViewerFrame.MULTI_MODE) {
				btnCopySeq.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
						cb.setContents(new StringSelection(theMultiPanel.getSelectedSequence()), null);
	
					}
	
				});
			}
			else {
				btnCopySeq.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						String copySeq = "";
						for(int x=0; x<thePairwisePanels.length && copySeq.length() == 0; x++) {
							if(thePairwisePanels[x].hasSelection())
								copySeq = thePairwisePanels[x].getSelectedSequence();
						}					
						Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
						cb.setContents(new StringSelection(copySeq), null);

					}
				});
			}
			theRow.add(menuHorzRatio);
			theRow.add(Box.createHorizontalStrut(10));
			theRow.add(btnShowType);
			theRow.add(Box.createHorizontalStrut(10));
			theRow.add(btnCopySeq);

			/** CAS 2/24/13 removing for this release 
			if(nMode == ViewerFrame.MULTI_MODE) {
				btnExport = new JButton("Export");
				btnExport.setBackground(Globals.PROMPTCOLOR);
				btnExport.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						if(theMultiPanel != null)
							theMultiAlignmentData.writeMuscleCache();
						else System.err.println("Internal error: not theMultiPanel");
					}
				});
				theRow.add(Box.createHorizontalStrut(10));
				theRow.add(btnExport);			
			}
			**/
			theRow.setMaximumSize(theRow.getPreferredSize());
			return theRow;
		}
		
		private JPanel getPairwiseButtonRow() {
			JPanel theRow = new JPanel();
			theRow.setLayout(new BoxLayout(theRow, BoxLayout.LINE_AXIS));
			theRow.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			theRow.setAlignmentX(LEFT_ALIGNMENT);
			
			btnShowAll = new JButton("Show All");
			btnShowAll.setEnabled(false);
			btnShowAll.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			btnShowAll.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					showAllPairwise();
					unselectAll();
					refreshPairwiseButtons();
				}
			});
			btnShowAllPairs = new JButton("Show All Pairs");
			btnShowAllPairs.setEnabled(false);
			btnShowAllPairs.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			btnShowAllPairs.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					showSelectedPairs(false);
					unselectAll();
					refreshPairwiseButtons();
				}
			});
			btnShowOnlyPairs = new JButton("Show Only Pairs");
			btnShowOnlyPairs.setEnabled(false);
			btnShowOnlyPairs.setBackground(theParentFrame.getSettings().getFrameSettings().getBGColor());
			btnShowOnlyPairs.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					showSelectedPairs(true);
					unselectAll();
					refreshPairwiseButtons();
				}
			});
			
			btnShowHelp = new JButton("Help");
			btnShowHelp.setAlignmentX(Component.RIGHT_ALIGNMENT);
			btnShowHelp.setBackground(UserPrompt.PROMPT); // CAS 4/22/11
			btnShowHelp.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					showPairwiseHelp();
				}
			});
			
			theRow.add(btnShowAll);
			theRow.add(Box.createHorizontalStrut(5));
			theRow.add(btnShowAllPairs);
			theRow.add(Box.createHorizontalStrut(5));
			theRow.add(btnShowOnlyPairs);
			theRow.add(Box.createHorizontalStrut(15));
			theRow.add(btnShowHelp);

			theRow.setMaximumSize(theRow.getPreferredSize());
			return theRow;
		}
		
		private void unselectAll() {
			for(int x=0; x<thePairwisePanels.length; x++) {
				thePairwisePanels[x].selectNone();
			}
		}
		
		private void showSelectedPairs(boolean pairsOnly) {
			String [] selectedIDs = getSelectedIDsPairwise();
			for(int x=0; x<thePairwisePanels.length; x++) {
				thePairwisePanels[x].setVisible(thePairwisePanels[x].hasContigIDs(selectedIDs, pairsOnly));
			}
		}
		
		private void showAllPairwise() {
			for(int x=0; x<thePairwisePanels.length; x++) {
				thePairwisePanels[x].setVisible(true);
			}
		}
		
		private void refreshPanels() {
			if(nMode == ViewerFrame.PAIR_MODE) 
				refreshPairwisePanels();
			else
				refreshMultiPanels();
		}
		
		private void refreshMultiButtons() {
			if(theMultiPanel.getNumSequencesSelected() == 1)
				btnCopySeq.setEnabled(true);
			else
				btnCopySeq.setEnabled(false);
		}
		
		private void refreshPairwiseButtons() {
			boolean allVisible = true;
			
			for(int x=0; x<thePairwisePanels.length && allVisible; x++) {
				allVisible = thePairwisePanels[x].isVisible();
			}
			if(allVisible)
				btnShowAll.setEnabled(false);
			else
				btnShowAll.setEnabled(true);
			
			int numSel = getNumSelectedIDsPairwise();
			if(numSel > 0)
				btnShowAllPairs.setEnabled(true);
			else
				btnShowAllPairs.setEnabled(false);
			
			if(numSel > 1)
				btnShowOnlyPairs.setEnabled(true);
			else
				btnShowOnlyPairs.setEnabled(false);
			
			if(numSel == 1)
				btnCopySeq.setEnabled(true);
			else
				btnCopySeq.setEnabled(false);
		}
		
		private String [] getSelectedIDsPairwise() {
			Vector<String> theIDs = new Vector<String> ();
			for(int x=0; x<thePairwisePanels.length; x++) {
				Vector<String> temp = thePairwisePanels[x].getSelectedContigIDs();
				if(temp.size() > 0) {
					Iterator<String> iter = temp.iterator();
					while(iter.hasNext()) {
						String ID = iter.next();
						if(!theIDs.contains(ID))
							theIDs.add(ID);
					}
				}
			}
			return theIDs.toArray(new String[theIDs.size()]);
		}

		private int getNumSelectedIDsPairwise() {
			Vector<String> theIDs = new Vector<String> ();
			for(int x=0; x<thePairwisePanels.length; x++) {
				Vector<String> temp = thePairwisePanels[x].getSelectedContigIDs();
				if(temp.size() > 0) {
					Iterator<String> iter = temp.iterator();
					while(iter.hasNext()) {
						String ID = iter.next();
						if(!theIDs.contains(ID))
							theIDs.add(ID);
					}
				}
			}
			return theIDs.size();
		}

		private void refreshPairwisePanels() {
			mainPanel.removeAll();
			try {
				boolean showText = btnShowType.getText().equals("Show Sequences");
				MenuMapper ratioSelection = (MenuMapper) menuHorzRatio.getSelectedItem();
				int ratio = ratioSelection.asInt();
				
				for(int x=0; x<thePairwisePanels.length; x++) {				
						thePairwisePanels[x].setBorderColor(Color.BLACK);
					
						thePairwisePanels[x].setBasesPerPixel(ratio);
						if(showText)
							thePairwisePanels[x].setDrawMode(AlignmentPanelBase.GRAPHICMODE);
						else
							thePairwisePanels[x].setDrawMode(AlignmentPanelBase.TEXTMODE);

						mainPanel.add(thePairwisePanels[x]);
				}
				mainPanel.add(Box.createVerticalStrut(40));
				LegendPanel lPanel = new LegendPanel();
				lPanel.setIsPair(true);
				mainPanel.add(lPanel);
				mainPanel.revalidate();
				mainPanel.repaint();
			} catch (Exception e) {
				e.printStackTrace();
				ErrorReport.reportError(e);
			}
		}
		
		private void refreshMultiPanels() {
			mainPanel.removeAll();
			try {
				boolean showText = btnShowType.getText().equals("Show Sequences");
				MenuMapper ratioSelection = (MenuMapper) menuHorzRatio.getSelectedItem();
				int ratio = ratioSelection.asInt();
				
				if(theMultiPanel != null) {
					theMultiPanel.setBorderColor(Color.BLACK);
					theMultiPanel.setBasesPerPixel(ratio);
					if(showText)
						theMultiPanel.setDrawMode(AlignmentPanelBase.GRAPHICMODE);
					else
						theMultiPanel.setDrawMode(AlignmentPanelBase.TEXTMODE);
					
					mainPanel.add(theMultiPanel);

					mainPanel.add(Box.createVerticalStrut(40));
					LegendPanel lPanel = new LegendPanel();
					lPanel.setIsPair(true);
					mainPanel.add(lPanel);
				} else {
					mainPanel.add(new JLabel("No Sequences"));
				}
				
				mainPanel.revalidate();
				mainPanel.repaint();
			} catch (Exception e) {
				e.printStackTrace();
				ErrorReport.reportError(e);
			}
		}
		
		private void showPairwiseHelp() {
			UserPrompt.displayInfo("Pairwise Alignment Help", HELP_TEXT_PAIR_ALIGN);
		}
			
		private void createPairwisePanels() {
			thePairwisePanels = new PairwiseAlignmentPanel[thePairwiseAlignmentData.length];
			for(int x=0; x<thePairwisePanels.length; x++) {
				thePairwisePanels[x] = new PairwiseAlignmentPanel(theParentFrame, thePairwiseAlignmentData[x], 10, 10, 10, 10);
				thePairwisePanels[x].setAlignmentY(Component.LEFT_ALIGNMENT);
			}
		}
		
		private void createMultiAlignPanels() {
			theMultiPanel = new MultipleAlignmentPanel(theParentFrame, theMultiAlignmentData, 10, 10, 10, 10);
			theMultiPanel.setAlignmentY(Component.LEFT_ALIGNMENT);
		}
		
		private void createMainPanel() {
			scroller = new JScrollPane ( );
			scroller.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
			scroller.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED );		
			scroller.addMouseListener(new MouseAdapter() {
				public void mousePressed(MouseEvent e) {
					handleClick(e);
				}
			});	
			
			mainPanel = new JPanel();
			
			mainPanel.setLayout( new BoxLayout ( mainPanel, BoxLayout.Y_AXIS ) );
			mainPanel.setBackground( Globals.BGCOLOR );

			mainPanel.setAlignmentX(LEFT_ALIGNMENT);
			
			scroller.setViewportView( mainPanel );
			
			refreshPanels();
		}
		
		private void handleClick(MouseEvent e) {
			if(nMode == ViewerFrame.PAIR_MODE)
				handleClickForPairwise(e);
			else
				handleClickForMultiple(e);
		}
		
		private void handleClickForPairwise(MouseEvent e) {
			// Convert to view relative coordinates
			int viewX = (int) (e.getX() + scroller.getViewport().getViewPosition().getX());
			int viewY = (int) (e.getY() + scroller.getViewport().getViewPosition().getY());
			
			// Go through  all the panels and see which one was clicked on:
			for(int x=0; x<thePairwisePanels.length; x++)
			{
				// Get the panel and convert to panel relative coordinates
				int nPanelX = viewX - thePairwisePanels[x].getX();
				int nPanelY = viewY - thePairwisePanels[x].getY();
				
				if ( thePairwisePanels[x].contains( nPanelX, nPanelY ) )
					// Click is in current panel, let the object handle it
					thePairwisePanels[x].handleClick( e, new Point( nPanelX, nPanelY ) );
				else
					// Clear all selections in the panel unless shift or control are down
					if ( !e.isShiftDown() && !e.isControlDown() )
						thePairwisePanels[x].selectNone();
			}
			
			refreshPairwiseButtons();
		}
		
		private void handleClickForMultiple(MouseEvent e) {
			if(theMultiPanel != null) {
				// Convert to view relative coordinates
				int viewX = (int) (e.getX() + scroller.getViewport().getViewPosition().getX());
				int viewY = (int) (e.getY() + scroller.getViewport().getViewPosition().getY());
				
				// Get the panel and convert to panel relative coordinates
				int nPanelX = viewX - theMultiPanel.getX();
				int nPanelY = viewY - theMultiPanel.getY();
		
				if ( theMultiPanel.contains( nPanelX, nPanelY ) )
					// Click is in current panel, let the object handle it
					theMultiPanel.handleClick( e, new Point( nPanelX, nPanelY ) );
				else
					// Clear all selections in the panel unless shift or control are down
					if ( !e.isShiftDown() && !e.isControlDown() ) {
						theMultiPanel.selectNoRows();
						theMultiPanel.selectNoColumns();
					}
				
				refreshMultiButtons();
			}
		}

		private int nMode = -1;
		private ViewerFrame theParentFrame = null;
		//Display panels
		private JScrollPane scroller = null;
		
		//Main panels for the tab
		private JPanel buttonPanel = null;
		private JPanel mainPanel = null;
		
		//UI controls for the button panel
		private JComboBox menuHorzRatio = null;
		private JButton btnShowType = null;
		
		private JButton btnCopySeq = null;
		private JButton btnShowAll = null;
		private JButton btnShowAllPairs = null;
		private JButton btnShowOnlyPairs = null;
		private JButton btnShowHelp = null;
		
		private JButton btnExport = null;
		
		//Controls for progress/cancelling action
		private JTextField progressField = null;
		private JButton btnCancel = null;
		
		//Thread used for building the sequence data
		private Thread theThread = null;
		private boolean bRunThread = false;
		
		//Pairwise alignment data holders
		private AlignmentData [] thePairwiseAlignmentData = null;
		private PairwiseAlignmentPanel [] thePairwisePanels = null;
		
		//Multiple alignment dataholders
		private MultiAlignmentData theMultiAlignmentData = null;
		private MultipleAlignmentPanel theMultiPanel = null;
	}
